package com.wuxi.common.log.asp;

import com.wuxi.common.exception.exceptionInfo.DbException;
import com.wuxi.common.log.LogHandler;
import com.wuxi.common.log.annotation.OperationLog;
import com.wuxi.common.log.pojo.SysOperationLog;
import com.wuxi.common.utils.UserContext;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.servlet.http.HttpServletRequest;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import java.lang.reflect.Method;
import java.time.LocalDateTime;
import java.util.Arrays;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 操作日志切面，通过AOP实现日志记录
 */
@Slf4j
@Aspect
@Component
@RequiredArgsConstructor
public class OperationLogAspect {

    private final LogHandler logHandler;

    @Pointcut("@annotation(com.wuxi.common.log.annotation.OperationLog)")
    public void logPointCut() {}

    @Around("logPointCut()")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        long startTime = System.currentTimeMillis();
        SysOperationLog sysLog = new SysOperationLog();
        sysLog.setOperationTime(LocalDateTime.now());

        // 获取请求IP
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        if (attributes != null) {
            HttpServletRequest request = attributes.getRequest();
            sysLog.setClientIp(request.getRemoteAddr());
        }

        // 获取方法和类信息
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();
        Class<?> targetClass = method.getDeclaringClass();
        sysLog.setMethod(targetClass.getName() + "." + method.getName());

        // 存储参数数组的字符串表示（如"[LoginDTO(username=xxx, password=xxx)]"）
        sysLog.setParams(Arrays.toString(joinPoint.getArgs()));

        // 处理注解信息（module和description）
        OperationLog operationLog = method.getAnnotation(OperationLog.class);

        // 处理module
        String module = operationLog.module();
        if (module.isEmpty()) {
            Tag apiAnnotation = targetClass.getAnnotation(Tag.class);
            if (apiAnnotation != null && !apiAnnotation.name().isEmpty()) {
                module = apiAnnotation.name();
            } else {
                module = "默认模块";
            }
        }
        sysLog.setModule(module);

        // 处理description
        String description = operationLog.description();
        if (description.isEmpty()) {
            Operation apiOpAnnotation = method.getAnnotation(Operation.class);
            if (apiOpAnnotation != null) {
                description = apiOpAnnotation.summary();
            } else {
                description = "默认操作";
            }
        }
        sysLog.setDescription(description);

        // 核心修复：获取用户名（根据login方法的参数字符串提取）
        if ("login".equals(method.getName())) {
            // 直接使用params的字符串值提取用户名（无需强转，因为sysLog.getParams()是String类型）
            sysLog.setUsername(extractUsername(sysLog.getParams().toString()));
        } else {
            sysLog.setUsername(getCurrentUsername());
        }

        Object result = null;
        try {
            result = joinPoint.proceed();
            sysLog.setResult("成功");
        } catch (Exception e) {
            sysLog.setResult("失败");
            sysLog.setException(e.getMessage());
            throw e; // 继续抛出异常，不影响业务报错
        } finally {
            sysLog.setCostTime(System.currentTimeMillis() - startTime);
            saveOperationLog(sysLog);
        }

        return result;
    }

    /**
     * 获取当前登录用户名
     */
    private String getCurrentUsername() {
        String user = UserContext.getUser();
        return user == null ? "system" : user;
    }

    /**
     * 保存操作日志到数据库
     */
    private void saveOperationLog(SysOperationLog log) {
        try {
            logHandler.saveOperationLog(log);
        } catch (Exception e) {
            throw new DbException("记录系统日志失败：", e);
        }
    }

    /**
     * 从登录参数字符串中提取用户名
     * 适配格式："[LoginDTO(username=xxx, password=xxx)]" 或 "[username, password]"
     */
    public static String extractUsername(String loginParams) {
        if (loginParams == null || loginParams.trim().isEmpty()) {
            return "未知用户";
        }

        // 正则表达式：匹配 username=xxx 格式（优先处理对象参数）
        Pattern pattern = Pattern.compile("username=([^,)]+)");
        Matcher matcher = pattern.matcher(loginParams);
        if (matcher.find()) {
            return matcher.group(1).trim();
        }

        // 若未匹配到对象参数，尝试匹配第一个字符串参数（适用于login(String username, String password)）
        // 格式示例："[zhangsan, 123456]" → 提取第一个参数作为用户名
        Pattern simplePattern = Pattern.compile("\\[(.*?),");
        Matcher simpleMatcher = simplePattern.matcher(loginParams);
        if (simpleMatcher.find()) {
            return simpleMatcher.group(1).trim();
        }

        return "未知用户";
    }
}
